import type { ipcRenderer } from "electron";
import type fsp from "node:fs/promises";
import type { DownloadCompleteArgs, DownloadParam, DownloadProgressArgs, HttpResponse } from "@common/http-types.ts";
import type { UnzipCompleteArgs, UnzipFileArgs } from "@common/archives-file-types.ts";

export interface IpcRendererInvoker {
  /**
   * 监听事件
   * @param event 事件名称
   * @param listener 事件回调,ipcRenderer回调的第一个参数事件对象{@link Electron.IpcRendererEvent}已经移除,使用时不要考虑该参数
   * @returns 事件ID 函数从前端传到preload脚本时,地址上不是同一个函数，会导致事件解绑失败,因此需要保存起来，并分配ID，通过事件ID来解绑
   */
  on(event: string, listener: (...args: any[]) => any): number;

  /**
   * 解绑事件
   * @param event 事件名称
   * @param eventId 事件ID
   */
  off(event: string, eventId?: number): void;

  send(...args: Parameters<typeof ipcRenderer.send>): void;

  invoke(...args: Parameters<typeof ipcRenderer.invoke>): Promise<any>;

  invokeNode<T = any>(api: string, ...args: any[]): Promise<T>;

  invokeNodeChain<T = any>(args: ([string, any[] | undefined] | [string])[]): Promise<T>;

  eventNames(): (string | symbol)[];

  listenerCount(eventName: string): number;
}

export interface RendererShell extends Omit<Electron.Shell, "beep" | "readShortcutLink" | "writeShortcutLink"> {
  beep(): Promise<void>;

  readShortcutLink(shortcutPath: string): Promise<Electron.ShortcutDetails>;

  writeShortcutLink(shortcutPath: string, operation: "create" | "update" | "replace", options: Electron.ShortcutDetails): Promise<boolean>;

  /**
   * 使用系统编辑器打开文件
   * @param filePath 文件路径
   * @param preferVsc 是否优先使用VSCode
   */
  openFileViaEditor(filePath: string, preferVsc?: boolean): void;
}

type NativeImageType = typeof Electron.NativeImage;

export interface RendererNativeImage extends NativeImageType {}

export interface RendererFileSystem {
  /**
   * 判断文件或目录是否存在
   * @param path
   */
  exists(path: string): Promise<boolean>;

  /**
   * 判断文件或目录是否存在, 以文件读取权限判断, 能读则存在
   * @param path
   */
  exists1(path: string): Promise<boolean>;

  readFile(...args: Parameters<typeof fsp.readFile>): Promise<Uint8Array>;

  readFileText(...args: Parameters<typeof fsp.readFile>): Promise<string>;

  readFileJson<T = any>(...args: Parameters<typeof fsp.readFile>): Promise<T>;

  writeFile(...args: Parameters<typeof fsp.writeFile>): Promise<void>;

  writeBlob(file: string, blob: Blob): Promise<void>;

  mkdir(...args: Parameters<typeof fsp.mkdir>): Promise<string | undefined>;

  rm(...args: Parameters<typeof fsp.rm>): Promise<void>;

  copyFile(...args: Parameters<typeof fsp.copyFile>): Promise<void>;

  cp(...args: Parameters<typeof fsp.cp>): Promise<void>;

  readdir(path: string, options?: ReadDirOptions): Promise<string[]>;

  readlink(path: string): Promise<string>;

  symlink(...args: Parameters<typeof fsp.symlink>): Promise<void>;

  link(...args: Parameters<typeof fsp.link>): Promise<void>;

  unlink(...args: Parameters<typeof fsp.unlink>): Promise<void>;

  rename(...args: Parameters<typeof fsp.rename>): Promise<void>;
}

/**
 * 读取文件夹选项
 * @see {@link FastGlob.Options}
 */
export interface ReadDirOptions {
  onlyDirectories?: boolean;
  onlyFiles?: boolean;
  depth?: number;
  filter?: string | string[];
  ignore?: string[];
  dot?: boolean;
}

export interface RendererDialog {
  showOpenDialog(options: Electron.OpenDialogOptions): Promise<Electron.OpenDialogReturnValue>;

  showOpenDirectoryDialog(options?: Partial<Electron.OpenDialogOptions>): Promise<Electron.OpenDialogReturnValue>;

  showSaveDialog(options: Electron.SaveDialogOptions): Promise<Electron.SaveDialogReturnValue>;

  showMessageBox(options: Electron.MessageBoxOptions): Promise<Electron.MessageBoxReturnValue>;

  showErrorBox(title: string, content: string): void;
}

export interface DownloadArgs extends DownloadParam {
  // 下载进度回调
  progress?: (e: DownloadProgressArgs) => void;
}

export interface HttpRequestOptions extends RequestInit {
  timeout?: number;
}

export interface RendererHttpInvoker {
  get(url: string, options?: HttpRequestOptions): Promise<Uint8Array>;

  getText(url: string, options?: HttpRequestOptions): Promise<HttpResponse<string>>;

  getJson<T = any>(url: string, options?: HttpRequestOptions): Promise<HttpResponse<T>>;

  post(url: string, options?: HttpRequestOptions): Promise<Uint8Array>;

  postText(url: string, body: any, options?: HttpRequestOptions): Promise<HttpResponse<string>>;

  postJson<T = any>(url: string, body: any, options?: HttpRequestOptions): Promise<HttpResponse<T>>;

  /**
   * 提交下载文件任务
   * @param param
   */
  downloadFile(param: DownloadParam): void;

  /**
   * 下载文件
   * @param args
   */
  download(args: DownloadArgs): Promise<DownloadCompleteArgs>;

  /**
   * 取消文件下载
   * @param id 任务ID
   */
  cancelDownload(id: string): void;
}

export interface RendererArchivesInvoker {
  /**
   * 解压文件
   * @param args
   */
  unzip(args: UnzipFileArgs): Promise<UnzipCompleteArgs>;

  /**
   * 取消解压
   * @param id 任务ID
   */
  cancelUnzip(id: string): void;
}

export interface ChildProcessReturn {
  output: string;
  errorOutput: string;
}

export interface RendererChildProcessInvoker {
  /**
   * 执行命令
   * @param cmd
   * @param options
   */
  execCmd(cmd: string, options?: import("node:child_process").ExecOptions): Promise<ChildProcessReturn>;

  /**
   * 执行命令(sudo)
   * @param cmd
   * @param options
   */
  execCmdSudo(cmd: string, options?: import("node:child_process").ExecOptions): Promise<ChildProcessReturn>;

  /**
   * 执行程序/命令
   * @param cmd 程序路径/命令
   * @param args 参数
   */
  spawn(cmd: string, args?: string[]): Promise<ChildProcessReturn>;

  /**
   * 以管理员身份执行程序/命令
   * @param cmd 程序路径/命令
   * @param args 参数
   */
  sudo(cmd: string, args?: string[]): Promise<ChildProcessReturn>;

  /**
   * 执行项目(cmd-tools)目录下的工具程序
   * @param cmd 程序名称
   * @param args 参数
   */
  execCmdTool(cmd: string, args?: string[]): Promise<ChildProcessReturn>;

  /**
   * 以管理员身份执行项目(cmd-tools)目录下的工具程序
   * @param cmd 程序名称
   * @param args 参数
   */
  execCmdToolSudo(cmd: string, args?: string[]): Promise<ChildProcessReturn>;

  /**
   * 执行文件
   * @param file 文件路径
   * @param args 参数
   * @param options 选项
   */
  execFile(file: string, args?: string[], options?: import("node:child_process").ExecFileOptions): Promise<ChildProcessReturn>;
}

export interface ElectronNative {
  /**
   * IpcRenderer封装
   */
  ipc: IpcRendererInvoker;
  /**
   * 同electron.webUtils一致
   */
  webUtils: Electron.WebUtils;
  /**
   * 对electron.shell的封装,部分方法变为异步调用
   */
  shell: RendererShell;
  /**
   * 原生图片操作
   */
  nativeImage: RendererNativeImage;
  /**
   * 原生对话框操作
   */
  dialog: RendererDialog;
  /**
   * 文件操作
   */
  fs: RendererFileSystem;
  /**
   * 子进程操作
   */
  cp: RendererChildProcessInvoker;
  /**
   * 进程对象
   */
  process: NodeJS.Process;
  /**
   * http请求
   */
  http: RendererHttpInvoker;
  /**
   * 压缩文件操作
   */
  archives: RendererArchivesInvoker;
}
